package com.example.proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 以文本的形式得到类的各个组成部分, 可用于逆向分析, 如以下几个特殊的类: 
 * <li>基本数据类型: {@code int.class}</li> 
 * <li>基本数据类型数组: {@code int[].class}</li>
 * <li>枚举: {@link Enum}</li>
 * <li>注解: {@link Override}</li>
 * <li>泛型类: 调用{@link #getClassText(Object)}可知运行时类型擦除</li>
 */
public class ClassParser {
	private ClassParser() {
		throw new RuntimeException("can't instantiate this class!");
	}

	/**
	 * 以文本的形式得到类的所有成员
	 *
	 * @param clazz
	 * @return
	 */
	public static String getClassText(Class<?> clazz) {
		StringBuffer sb = new StringBuffer();
		// class
		sb.append(getClassDeclaration(clazz));
		sb.append(" {\n\n");

		// field
		sb.append(getFieldsDeclaration(clazz));

		// constructors
		sb.append(getConstructorsDeclaration(clazz));

		// methods
		sb.append(getMethodsDeclaration(clazz));

		// end class
		sb.append("}");
		return sb.toString();
	}

	public static String getClassText(Object object) {
		return getClassText(object.getClass());
	}

	public static String getClassText(String className)
			throws ClassNotFoundException {
		return getClassText(Class.forName(className));
	}

	/**
	 * 得到方法声明
	 *
	 * @param clazz
	 * @return
	 */
	public static String getMethodsDeclaration(Class<?> clazz) {
		StringBuffer sb = new StringBuffer();
		Method[] methods = clazz.getDeclaredMethods();
		if (appendable(methods)) {
			String format = "\t%s %s %s(%s)%s;\n";
			for (int i = 0; i < methods.length; i++) {
				Method method = methods[i];
				String modifier = getModifier(method.getModifiers());
				String returnType = method.getReturnType().getName();
				String name = method.getName();
				String parameters = list(method.getParameterTypes());
				String exceptions = list(method.getExceptionTypes());
				exceptions = exceptions.equals("") ? "" : " throws ".concat(exceptions);
				sb.append(String.format(format, modifier, returnType, name,
						parameters, exceptions));
			}
			sb.append("\n");
		}
		return sb.toString();
	}

	public static String getMethodsDeclaration(Object object) {
		return getMethodsDeclaration(object.getClass());
	}

	public static String getMethodsDeclaration(String className)
			throws ClassNotFoundException {
		return getMethodsDeclaration(Class.forName(className));
	}

	/**
	 * 得到构造方法声明
	 *
	 * @param clazz
	 * @return
	 */
	public static String getConstructorsDeclaration(Class<?> clazz) {
		StringBuffer sb = new StringBuffer();
		Constructor<?>[] constructors = clazz.getDeclaredConstructors();
		if (appendable(constructors)) {
			String format = "\t%s %s(%s)%s;\n";
			for (Constructor<?> constructor : constructors) {
				String modifier = getModifier(constructor.getModifiers());
				String name = constructor.getName();
				String parameters = list(constructor.getParameterTypes());
				String exceptions = list(constructor.getExceptionTypes());
				exceptions = exceptions.equals("") ? "" : " throws ".concat(exceptions);
				sb.append(String.format(format, modifier, name, parameters, exceptions));
			}
			sb.append("\n");
		}
		return sb.toString();
	}

	public static String getConstructorsDeclaration(Object object) {
		return getConstructorsDeclaration(object.getClass());
	}

	public static String getConstructorsDeclaration(String className)
			throws ClassNotFoundException {
		return getConstructorsDeclaration(Class.forName(className));
	}

	/**
	 * 得到字段声明
	 *
	 * @param clazz
	 * @return
	 */
	public static String getFieldsDeclaration(Class<?> clazz) {
		StringBuffer sb = new StringBuffer();
		Field[] fields = clazz.getDeclaredFields();
		if (appendable(fields)) {
			String format = "\t%s %s %s;\n";
			for (Field field : fields) {
				sb.append(String.format(format,
						getModifier(field.getModifiers()), field.getType(),
						field.getName()));
			}
			sb.append("\n");
		}
		return sb.toString();
	}

	public static String getFieldsDeclaration(Object object) {
		return getFieldsDeclaration(object.getClass());
	}

	public static String getFieldsDeclaration(String className)
			throws ClassNotFoundException {
		return getFieldsDeclaration(Class.forName(className));
	}

	/**
	 * 得到类型声明
	 *
	 * @param clazz
	 * @return
	 */
	public static String getClassDeclaration(Class<?> clazz) {
		// class modifiers
		String classModifier = getModifier(clazz.getModifiers());
		StringBuffer sb = new StringBuffer(classModifier);

		// class name
		sb.append(" class ").append(clazz.getName());

		// super class name
		Class<?> superclass = clazz.getSuperclass();
		if (superclass != null)
			sb.append(" extends ").append(superclass.getName());

		// Interfaces
		Class<?>[] interfaces = clazz.getInterfaces();
		if (appendable(interfaces)) {
			if (classModifier.contains("interface")) {
				// 接口多继承
				sb.append(" extends ").append(list(interfaces));
			} else {
				sb.append(" implements ").append(list(interfaces));
			}
		}
		return sb.toString();
	}

	public static String getClassDeclaration(Object object) {
		return getClassDeclaration(object.getClass());
	}

	public static String getClassDeclaration(String className)
			throws ClassNotFoundException {
		return getClassDeclaration(Class.forName(className));
	}

	private static String getModifier(int modifier) {
		return Modifier.toString(modifier);
	}

	private static String list(Class<?>[] clsArr) {
		if (appendable(clsArr)) {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < clsArr.length; i++) {
				sb.append(clsArr[i].getName()).append(", ");
			}
			sb.delete(sb.length() - 2/* ", ".length() */, sb.length());
			return sb.toString();
		}
		return "";
	}

	private static boolean appendable(Object[] paraList) {
		return paraList != null && paraList.length > 0;
	}
}